﻿using System;
using System.Collections.Generic;
using System.IO;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Core.Network.Download.Protocol.Data;
using HK.Core.Serializable.Data;
using HK.Core.Serializable.Protocol.Data;
using HK.Core.Utils;
using HK.Editor.GUIEx.TreeView.Data;
using HK.Editor.Network.Download.Protocol.Data;
using UnityEngine;
using UnityEngine.Serialization;

namespace HK.Editor.Network.Download.Data
{
    /// <summary>
    /// 下载验证Element
    /// </summary>
    [Serializable]
    public sealed class DownloadVerifyElement : TreeBranch<DownloadVerifyElement>, IDownloadVerifyElement, IEquatable<DownloadVerifyElement>
    {

#region Create

        /// <summary>
        /// 创建下载验证信息
        /// <para>* 根节点</para>
        /// </summary>
        /// <returns>下载验证信息</returns>
        public static DownloadVerifyElement CreateRoot()
        {
            return new DownloadVerifyElement(0, "Root", -1);
        }

        /// <summary>
        /// 创建下载验证信息
        /// </summary>
        /// <param name="iFileDesc">下载文件描述</param>
        /// <param name="iDownloadBaseUrl">下载Url(Base)</param>
        /// <returns>下载验证信息</returns>
        public static DownloadVerifyElement Create(IDownloadFileDesc iFileDesc, string iDownloadBaseUrl)
        {
            var downloadUrl = Path.Combine(iDownloadBaseUrl, iFileDesc.Path);
            return new DownloadVerifyElement
            {
                Name = UtilsIo.GetFileNameByUrl(downloadUrl),
                Url = downloadUrl, Crc = iFileDesc.Crc, Size = iFileDesc.Size
            };
        }

#endregion
        
        /// <summary>
        /// 下载验证Element
        /// </summary>
        public DownloadVerifyElement() : this(0, "Root", -1) {}
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iId">Id</param>
        /// <param name="iName">Name</param>
        /// <param name="iDepth">深度</param>
        private DownloadVerifyElement (int iId, string iName, int iDepth) : base(iId, iName, iDepth) { }

        [SerializeField]
        private uint crc = 0;
        /// <summary>
        /// 校验码 - Crc
        /// </summary>
        public uint Crc
        {
            get => crc; 
            private set => crc = value;
        }

        [SerializeField]
        private long size = 0L;
        /// <summary>
        /// 大小
        /// <para>* 单位 : Crc</para>
        /// </summary>
        public long Size 
        {
            get => size; 
            private set => size = value;
        }

        /// <summary>
        /// 下载进度
        /// </summary>
        public float DownloadProgress { get; private set; } = 0.0f;
        
        /// <summary>
        /// 解压/解密进度
        /// </summary>
        public float DecompressedProgress { get; private set; } = 0.0f;

        [SerializeField]
        private string url = null;
        /// <summary>
        /// 下载地址
        /// </summary>
        public string Url 
        {
            get => url; 
            private set => url = value;
        }
        
        /// <summary>
        /// 唯一标识Element的Key
        /// </summary>
        public string Key => url;
        
#region State

        /// <summary>
        /// 状态
        /// </summary>
        public int State { get; private set; } = (int)DownloadVerifyState.None;
        
        /// <summary>
        /// 下载中
        /// </summary>
        public bool Downloading
        {
            get => UtilsBytes.CheckBytes(State, (int)DownloadVerifyState.Downloading);
            set
            {
                var onOff = value;
                State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Downloading, onOff);
                if (onOff)
                {
                    State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Downloaded, false);
                }
            }
        }
        
        /// <summary>
        /// 已下载
        /// </summary>
        public bool Downloaded 
        {
            get => UtilsBytes.CheckBytes(State, (int)DownloadVerifyState.Downloaded);
            set
            {
                var onOff = value;
                State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Downloaded, onOff);
                if (onOff)
                {
                    State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Downloading, false);
                }
            }
        }
        
        /// <summary>
        /// 解压/解密中
        /// </summary>
        public bool Decompressing 
        {
            get => UtilsBytes.CheckBytes(State, (int)DownloadVerifyState.Decompressing);
            set
            {
                var onOff = value;
                State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Decompressing, onOff);
                if (onOff)
                {
                    State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Decompressed, false);
                }
            }
        }
        
        /// <summary>
        /// 已解压/解密
        /// </summary>
        public bool Decompressed 
        {
            get => UtilsBytes.CheckBytes(State, (int)DownloadVerifyState.Decompressed);
            set
            {
                var onOff = value;
                State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Decompressed, onOff);
                if (onOff)
                {
                    State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Decompressing, false);
                }
            }
        }
        
        /// <summary>
        /// 成功
        /// </summary>
        public bool Succeeded 
        {
            get => UtilsBytes.CheckBytes(State, (int)DownloadVerifyState.Succeeded);
            set => State = UtilsBytes.SetBytes(State, (int)DownloadVerifyState.Succeeded, value);
        }

#endregion
        
#region Equals

        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iDefine">宏定义</param>
        /// <returns>true:相同; false:不相同;</returns>
        public bool Equals(DownloadVerifyElement iDefine)
        {
            if (null == iDefine || !iDefine.Valid) return false;

            if (UtilsString.Diff(url, iDefine.Url)) return false;
            if (crc != iDefine.Crc) return false;
            if (size != iDefine.Size) return false;
            return true;
        }

#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IDownloadVerifyElement element)
            {
                crc = UpdateValue(crc, element.Crc, iImport);
                size = UpdateValue(size, element.Size, iImport);
                url = UpdateValue(url, element.Url, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid => base.Valid && !string.IsNullOrEmpty(Url);

        public override void Clear()
        {
            base.Clear();

            Crc = 0;
            Size = 0L;
            Url = null;
            
            State = (int)DownloadVerifyState.None;
        }
    }

    /// <summary>
    /// 下载验证数据
    /// </summary>
    [Serializable]
    public class DownloadVerifyData : ListJsonData<DownloadVerifyData, DownloadVerifyElement>, IDownloadVerifyData<DownloadVerifyElement>
    {

        [SerializeField]
        private string dateTxt = null;
        /// <summary>
        /// 日期
        /// <para>* 测试时频繁更新文件，此信息对检查是否是CDN缓存重要</para>
        /// </summary>
        public string Date
        {
            get => dateTxt;
            private set => dateTxt = value;
        }
        
        [SerializeField]
        private string author = null;
        /// <summary>
        /// 上传者/创建者
        /// </summary>
        public string Author 
        {
            get => author;
            private set => author = value;
        }
        
        [SerializeField]
        private SAssetVersion patchVer = SAssetVersion.Create();
        /// <summary>
        /// 补丁包版本
        /// </summary>
        public ISAssetVersion PathVer => patchVer;
        
        [SerializeField]
        private SAssetVersion originVer = SAssetVersion.Create();
        /// <summary>
        /// 母包版本
        /// </summary>
        public ISAssetVersion OriginVer => originVer;

        [SerializeField]
        private byte descVer = 0;
        /// <summary>
        /// 描述文件版本号
        /// </summary>
        public byte DescVer 
        {
            get => descVer;
            private set => descVer = value;
        }
        
        [SerializeField]
        private long totalSize = 0;
        /// <summary>
        /// 总大小
        /// <para>* 单位 : Byte</para>
        /// </summary>
        public long TotalSize 
        {
            get => totalSize;
            private set => totalSize = value;
        }
        
        [SerializeField]
        private uint crc = 0;
        /// <summary>
        /// 校验码 - Crc
        /// </summary>
        public uint Crc 
        {
            get => crc;
            private set => crc = value;
        }
        
        [SerializeField]
        private int totalCount = 0;
        /// <summary>
        /// 总个数
        /// <para>* 既:下载列表文件数</para>
        /// </summary>
        public int TotalCount 
        {
            get => totalCount;
            private set => totalCount = value;
        }

        /// <summary>
        /// 下载验证对象列表
        /// </summary>
        public List<DownloadVerifyElement> Targets => list;
        
        [SerializeField]
        private string downloadDir = null;
        /// <summary>
        /// 下载目录
        /// </summary>
        public string DownloadDir 
        {
            get => downloadDir;
            internal set => downloadDir = value;
        }
        
#region Token

        /// <summary>
        /// 负载Tag
        /// </summary>
        public string PayloadTag => GetType().Name;

#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IDownloadVerifyData<DownloadVerifyElement> verifyData)
            {
                dateTxt = UpdateValue(dateTxt, verifyData.Date, iImport);
                author = UpdateValue(author, verifyData.Author, iImport);

                dirty = patchVer.ApplyData(verifyData.PathVer);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }
                dirty = originVer.ApplyData(verifyData.OriginVer);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }

                descVer = UpdateValue(descVer, verifyData.DescVer, iImport);
                totalSize = UpdateValue(totalSize, verifyData.TotalSize, iImport);
                crc = UpdateValue(crc, verifyData.Crc, iImport);
                totalCount = UpdateValue(totalCount, verifyData.TotalCount, iImport);
                downloadDir = UpdateValue(downloadDir, verifyData.DownloadDir, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();

            dateTxt = null;
            author = null;
            patchVer.Clear();
            originVer.Clear();
            descVer = 0;
            totalSize = 0L;
            crc = 0;
            totalCount = 0;
            downloadDir = null;
        }
    }
}
